package org.noote.libs.sogle;

import java.util.ArrayList;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import org.noote.libs.sogle.helper.FPSCounter;


import android.content.Context;
import android.opengl.GLSurfaceView;
import android.opengl.GLU;
import android.view.MotionEvent;

public class Renderer implements GLSurfaceView.Renderer {

	protected Context _context = null;
	
	public Camera _camera = new Camera(0, 0, 0, 0, 0, 1);
	public ArrayList<Object3D> _listObjects = new ArrayList<Object3D>();
	public ArrayList<Light> _listLights = new ArrayList<Light>();

	protected int _height=320, _width=480;
	protected boolean bLighting = true;

    protected float fRunningTime = 0;
    protected long uTime = 0;
    
	public FPSCounter _fps = new FPSCounter(1.0f/8.0f); // Calcul FPS all quart of second
	
    public Renderer(Context context)
    {
    	_context = context;
    }
    
    public Context getContext()
    {
    	return _context;
    }
    
    public void onCreateScene(GL10 gl)
    {
    }
    
	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		onResize(width, height);
        
		gl.glViewport(0, 0, width, height);

		setPerspectiveProjection(gl);

		gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
	    gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glDepthFunc(GL10.GL_LEQUAL);
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
		gl.glShadeModel(GL10.GL_SMOOTH);
		gl.glDisable(GL10.GL_DITHER);
	}
	
	public void onResize(int width, int height)
	{
		_width = width;
		_height = height;
	}

    private float mBG_Red=0;
    private float mBG_Green=0;
    private float mBG_Blue=0;

	public void setBackGroundColor(float r, float g, float b) {
        mBG_Red = r;
        mBG_Green = g;
        mBG_Blue = b;
    }
	
	public void setPerspectiveProjection(GL10 gl)
	{
		// set up projection matrix
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity(); 
		GLU.gluPerspective(gl, 45.0f,
                (float) _width / (float) _height,
                0.1f, 250.0f);			
	    gl.glViewport(0, 0, _width, _height);
	}
	public void setOrthoProjection(GL10 gl)
	{
		// set up projection orth matrix ([-1,1], [-1,1], [0,100])
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		float ratio = _width / _height;
		gl.glOrthof(-1, 1, -1 / ratio, 1 / ratio, 0.01f, 100.0f);
	    gl.glViewport(0, 0, _width, _height);
	}
	public void set2DProjection(GL10 gl)
	{
		// set up projection matrix for 2d ([0, _width],[0, _height],[1, -1])
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
        gl.glOrthof(0, _width, 0, _height, 1.0f, -1.0f);
	    gl.glViewport(0, 0, _width, _height);
	}
	
	public void lighting(boolean bOn)
	{
		bLighting = bOn;
	}

	public void onTouchEvent(final MotionEvent event)
	{
	}
	
	public int getWidth()
	{
		return _width;
	}
	public int getHeight()
	{
		return _height;
	}

	@Override
	public void onDrawFrame(GL10 gl) {
		long _now=System.currentTimeMillis();
		float fTimeSlice=(_now - uTime)/1000.0f;
		
		if(uTime == 0) // first time :)
			onCreateScene(gl);
		else
		{
			fRunningTime += fTimeSlice;
			onFrame(fTimeSlice);
		}
        uTime = _now;
        
        _fps.update(fTimeSlice);
		
        _draw3D(gl, fTimeSlice);
        _draw2D(gl, fTimeSlice);
	}

	protected void _draw3D(GL10 gl, float fTimeSlice) {
		gl.glClearColor(mBG_Red, mBG_Green, mBG_Blue, 1.0f);
		gl.glClearDepthf(1.0f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
	    gl.glEnable(GL10.GL_COLOR_MATERIAL);
        
        setPerspectiveProjection(gl);
        
        // setup camera
        GLU.gluLookAt(gl,
        		_camera._position.x, _camera._position.y, _camera._position.z,
        		_camera._position.x+_camera._front.x, _camera._position.y+_camera._front.y, _camera._position.z+_camera._front.z,
        		_camera._up.x, _camera._up.y, _camera._up.z);

        // reset the matrix for 3d
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        
        // setup lighting !
        if(bLighting)
        {
        	// check if
	        gl.glEnable(GL10.GL_LIGHTING);
	    	//gl.glEnable(GL10.GL_NORMALIZE);
	        
	        int iLight=0;
	        for(Light l : _listLights)
	        {
	        	l.draw(gl, GL10.GL_LIGHT0+iLight);
	        	iLight++;
	        }
        }
        
        for(Object3D o : _listObjects)
        {
        	// TODO check if visible in camera scope !
        	// TODO split mesh with blend material and sort them by desc Z

        	o.draw(gl);
        }
	}
	
	protected void _draw2D(GL10 gl, float fTimeSlice) {
		// draw 2D (after 3d rendering) like GUI
	}

	public void onFrame(float fTimeSlice) {
		// Frame for animation
	}
}
